package com.hibox.util.payment;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.hibox.common.core.domain.AjaxResult;
import com.hibox.common.utils.ServletUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author WangFK
 * @version 1.0
 * @since 2023/7/29 15:39
 */
@Data
@Component
public class AlipayUtil {

    /**
     * alipay:
     * appId: 9021000123627059
     * appPrivateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCoA1zme7hvtg85MfJo5oyTytflSVYNBgU0Ykf+gJevLa4HAn8tgZ9EgsabpuP0imph4k7mZXWkMlgqUZj2zZqDYL1v8YfgU/iJ0mkccRfWJzjLt/oWwdXZHXYdEXfbo9kavtO7SaUDOmua+fHLYv5NGNGrFrHQO/FSKB2LxyFoZwkjvOOWZXPgm7zPt0LlDYrmvFyvd7CqNFxdrQcFAxeQPRTW0FQT4T5v34eJlsuaHgmY68vSczU/0QK6um196VZpoxRIO3GAaRwa5Nn3K9Ii718vN5i8tkoC2G8G9OgzCnfyEMgxDQQKy6pW+wuAiAB05TAN97S0wAoX7uyQo0ttAgMBAAECggEACaBfs0kFcUkiKCnHdOE4zsMBib6g8pAUvkKfU2K0zjG01ev7s3TI1lkT3hk62GkR3VflI2hOzECiMpKITCPNpZdmY0KYgW7uP59RrHKCZh/LLkj1SFaE1TLN8K5uiqQhrVmfsgxvKvcu8Ss/AmNCpNI2OTJMr9yvYACyaK7ZKC0fMAhf+Bb/nztLNEyAHi2V/XnpWcSd2fFPCNbKHec01JJU4WJoHlb5MJbABetMgreYBIb4Hd+vOj3YBQ+My7z8zWWg0wenPtCDSzCYn+4vOn71tXNxslnHh15tytKtaA6U1CI4VScj0FJ1QI82zETGkiMD7w49UEMSQcuyNSfIwQKBgQDrs17tgWORCPks4KbCT6t+lgukvDOeHaDwnfa19p2MSq+IPsez3UFCh7Ep3LDQrCjKYjDi/6L9yZLO2zrTjsyzowOlqFFDC4cASKmH7PL9F1l3+0D2ghlIfez/kvlGE3OPNX6e38yHHumTbgySdTqk8Gu82tELYn9ckbETAXo6vQKBgQC2e6VXVlJr3CPuHMMpnPiAJD8U09bQCiULv1CraPrvb+EIn/2dgO4lQFYji0QIkEcB+9O/7cGewNKJB/S8rxwNt6m2KhMRczIA2Ai/J0cjZqfRxI3E8cTloA53ewqMU0R+D5sPhYKwXNT16WCBq2hvKHcgkOGBimc63J+dGPG2cQKBgDaIcq8q35l/5P7gH1UXz8ri9mCv9pVfr4vcUGd7XqpF4WT5eYUA7Qdyk6fm2rX9Dxb8LulmUhS73Y6kpHCsOmpZjg926Q5FDYAgT7EWPoYWL+oVpMskAKuIDxx2qdvvxi3dJ6WkjBK7MTmeHaSJIP9mbNbuHa2vpV4Ki1ilX91VAoGAJ5sOd7Y0jVRqN/PmJ9H53VYAmvSfWufYwoPzbkCKtg0COmz/DoA9L7iW+X/wdCtcPgH6I13m+B3BlBw18f3PiOqj2vWmzdLCt4wr2dEcj4JoSg7u9h/DLFNg0G3UDEDGTNX2QZgolT6Qug6882fQcs/FizvmtcbkQNJBkkcnrwECgYEAwojoqD0BjV15km2v6mx4Oxj74eyyAzl8p38yZirmNkatIaAP1iWkpDdgLYbGfbRTW7aDCP7VuAT6KMBGhF3MMZ/qK/THqjXFpjtg28P4kfj1TcbsX4v7RD7+m5i18IwRfAZH4MYi84eG0uJy4ZV8dFIndrLP27VqGyv/9MKnl6o=
     * alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwUSisfOtqR/zh+jLbWD1Lw+q2Xoqt66heJuYKsiarmordYs7Y/bHuhZO2h8azenXmpfF9E0VVcPLqrUtPRy2LmVifk4Z5zVT4PsmggFS631FxpGRTvdhz+WsyDBozCkEzOgxJUz+mH9d3KSwBKmNzJ7ooC34yBnvxzX0nEv8HbjY9qlSWqYt31g8LSAsjIG5AM4VhdDGjzrnGaXtU1AapYK43kye/3EZMAK46cjtu2KrsvuuckmVDWptJwoKWTUnIcquQsYKC5PYIZ0g4GbY2J2t+ioiQbasdmKOPdjYPks69Y9cd9gnW9ItPxgScLLPZvlg28YL5l0jLbPU4BvKfwIDAQAB
     * notifyUrl:  http://6z2au9.natappfree.cc
     * returnUrl: http://localhost:3000/order/
     */
    // 商户appid
    @Value("${alipay.appId}")
    public String APPID;
    // 支付宝公钥
    @Value("${alipay.alipayPublicKey}")
    public String ALIPAY_PUBLIC_KEY;
    // 私钥 pkcs8格式的
    @Value("${alipay.appPrivateKey}")
    public String RSA_PRIVATE_KEY;
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径，不能加?id=123这类自定义参数，必须外网可以正常访问
    @Value("${alipay.notifyUrl}")
    public String notify_url;
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径，不能加?id=123这类自定义参数，必须外网可以正常访问 商户可以自定义同步跳转地址
    @Value("${alipay.returnUrl}")
    public String return_url;
    // 请求网关地址
    public String URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
    // 编码
    public String CHARSET = "UTF-8";
    // 返回格式
    public String FORMAT = "json";

    // 日志记录目录
    public String log_path = "/log";
    // RSA2
    public String SIGNTYPE = "RSA2";


    /**
     * 跳转支付页面 - > 返回付款信息
     * 如果想自定义同步跳转页面路径，只需在map中添加key:return_url value:同步跳转地址
     * 优先级 自定义（在map中定义的key：return_url）大于默认（在yml中定义的returnUrl）
     * map 中传递 out_trade_no 订单号 total_amount 金额 subject 支付名称
     *
     * @param map
     * @return
     * @throws AlipayApiException
     */
    public String pay(Map map) throws IOException {

        // 支付宝网关
        String serverUrl = URL;
        // APPID
        String appId = APPID;
        // 商户私钥, 即PKCS8格式RSA2私钥
        String privateKey = RSA_PRIVATE_KEY;
        // 格式化为 json 格式
        String format = FORMAT;
        // 字符编码格式
        String charset = CHARSET;
        // 支付宝公钥, 即对应APPID下的支付宝公钥
        String alipayPublicKey = ALIPAY_PUBLIC_KEY;
        // 签名方式
        String signType = SIGNTYPE;
        String returnUrl = return_url;
        // 页面跳转同步通知页面路径
        if (ObjectUtil.isNotEmpty(map.get("return_url"))) {
            returnUrl = map.get("return_url").toString();
        }

        // 服务器异步通知页面路径
        String notifyUrl = notify_url;

        // 1、获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(
                serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType);

        // 2、设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        // 页面跳转同步通知页面路径
        alipayRequest.setReturnUrl(returnUrl);
        // 服务器异步通知页面路径
        alipayRequest.setNotifyUrl(notifyUrl);
        map.put("product_code", "FAST_INSTANT_TRADE_PAY");
        alipayRequest.setBizContent(JSONUtil.toJsonStr(map));
        // 3、请求支付宝进行付款，并获取支付结果
        String AjaxResult = null;
        try {
            AjaxResult = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        // 执行请求，拿到响应的结果，返回给浏览器
        HttpServletResponse response = ServletUtils.getResponse();
        response.setContentType("text/html;charset=" + CHARSET);
        // 直接将完整的表单html输出到页面
        response.getWriter().write(AjaxResult);
        response.getWriter().flush();
        response.getWriter().close();
        // 返回付款信息
        return AjaxResult;
    }

    /**
     * 参数会转为map
     *
     * @param out_trade_no
     * @param total_amount
     * @param subject
     * @return
     * @throws AlipayApiException
     */
    public String pay(String out_trade_no, String total_amount, String subject) throws AlipayApiException, IOException {
        HashMap<String, Object> map = new HashMap<>();
        map.put("out_trade_no", out_trade_no);
        map.put("total_amount", total_amount);
        map.put("subject", subject);
        return pay(map);
    }

    /**
     * 异步通知 返回支付成功信息
     *
     * @return
     */
    public Map payNotify() {
        HttpServletRequest request = ServletUtils.getRequest();
        if (!request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            return AjaxResult.error("回调失败");
        }
        System.out.println("=========支付宝异步回调========");
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            params.put(name, request.getParameter(name));
        }
        String sign = params.get("sign");
        String content = AlipaySignature.getSignCheckContentV1(params);
        boolean checkSignature = false; // 验证签名
        try {
            checkSignature = AlipaySignature.rsa256CheckContent(content, sign, ALIPAY_PUBLIC_KEY, CHARSET);
        } catch (AlipayApiException e) {
            return AjaxResult.error("验签失败");
        }
        // 支付宝验签
        if (!checkSignature) {
            return AjaxResult.error("验签失败");
        }
        // 验签通过
        System.out.println("交易名称subject: " + params.get("subject"));
        System.out.println("交易状态trade_status: " + params.get("trade_status"));
        System.out.println("支付宝交易凭证号trade_no: " + params.get("trade_no"));
        System.out.println("商户订单号out_trade_no: " + params.get("out_trade_no"));
        System.out.println("交易金额total_amount: " + params.get("total_amount"));
        System.out.println("买家在支付宝唯一ID buyer_id: " + params.get("buyer_id"));
        System.out.println("买家付款时间gmt_payment: " + params.get("gmt_payment"));
        System.out.println("买家付款金额buyer_pay_amount: " + params.get("buyer_pay_amount"));
        return params;
    }


}
